package view;

import datacontainer.ImmuTable;
import factory.Factory;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import model.DataManager;
import model.exception.FileReadException;
import view.graph.AbstractVisualization;
import view.option.AbstractOption;


/**
 * 
 * @author Oren Bukspan
 * @author Michael Deng
 * @author Jei Min Yoo
 * @author Kannan Raju
 */
public class DataVisualizer {

    private static final JFileChooser OUR_CHOOSER = new JFileChooser(
                            System.getProperties().getProperty("user.dir"));
    private static final Dimension SIZE = new Dimension(600, 600);

    private DataManager myModel;
    private Factory<AbstractOption> myChartCreatorFactory;
    private AbstractVisualization myVisualization;
    private Factory<AbstractVisualization> myVisualizationFactory;
    private ImmuTable myData;
    private JFrame myFrame;
    private String mySchool;
    private String myDataPath;

    /**
     * The constructor for this class, takes in the DataManager and
     * initializes the JFrame and Visualization factories.
     * @param m the model attached to this view
     */
    public DataVisualizer (DataManager m) {
        myModel = m;
        myChartCreatorFactory = new Factory<AbstractOption>(
                "view.option", "Option creation error");
        myVisualizationFactory = 
                new Factory<AbstractVisualization>("view.graph", "Chart creation error");
        initializeFrame();
    }

    /**
     * Creates the Graph of a particular Visualization type.
     * @param type ENUM of the graph we are creating
     */
    public void createGraph (String type) {
        myVisualization = myVisualizationFactory.getObject(type);
    }

    /**
     * Takes in and stores the data for visualization.
     * @param data immuTable object we are getting data from
     */
    public void inputData (ImmuTable data) {
        myData = data;
        myVisualization.inputData(myData);
    }

    /**
     * Initializes the Canvas for the Visualization.
     * @param dim initialize size of the Visualization.
     * @return a new Canvas
     */
    private JComponent getVisualization (Dimension dim) {
        Canvas canvas = new Canvas(dim, myVisualization);
        return canvas;
    }

    /**
     * Updates and repaints the display
     */
    private void updateDisplay () {
        JComponent canvas = getVisualization(SIZE);
        myFrame.getContentPane().removeAll();
        myFrame.getContentPane().add(canvas);
        myFrame.repaint();
        myFrame.setTitle("GEDIVA Project - " + mySchool);
        myFrame.setVisible(true);
    }

    /**
     * Initializes the Jframe
     */
    private void initializeFrame () {
        myFrame = new JFrame();
        myFrame.setSize(SIZE);
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setMinimumSize(SIZE);
        myFrame.setLocationRelativeTo(null);
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(createFileMenu());
        menuBar.add(createDisplayMenu());
        myFrame.setJMenuBar(menuBar);
        myFrame.setVisible(true);
    }

    private JMenu createDisplayMenu () {
        JMenu display = new JMenu("Display");
        display.add(createBarMenuItem());
        display.add(createPieMenuItem());
        return display;
    }

    private JMenuItem createBarMenuItem () {
        JMenuItem temp = new JMenuItem("Bar");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                displayChart("BarData", myDataPath, mySchool);
            }
        });
        return temp;
    }

    private JMenuItem createPieMenuItem () {
        JMenuItem temp = new JMenuItem("Pie");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                displayChart("PieData", myDataPath, mySchool);
            }
        });
        return temp;
    }

    private JMenu createLoadMenu () {
        JMenu load = new JMenu("Load Data");
        load.add(createURLMenuItem());
        load.add(createCSVMenuItem());

        return load;
    }

    private JMenuItem createURLMenuItem () {
        JMenuItem temp = new JMenuItem("Load URL");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                myDataPath = JOptionPane.showInputDialog(myFrame, "Enter url:", "http://");
                initializeData(myDataPath);
            }
        });
        return temp;
    }

    private JMenuItem createCSVMenuItem () {
        JMenuItem temp = new JMenuItem("Load CSV");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                int response = OUR_CHOOSER.showOpenDialog(myFrame);
                if (response == JFileChooser.APPROVE_OPTION) {
                    myDataPath = OUR_CHOOSER.getSelectedFile().getPath();
                }
                initializeData(myDataPath);
            }

        });
        return temp;
    }

    private void initializeData (String path) {
        try {
            myModel.resetRawData(path);
            askForSchool();
        }
        catch (FileReadException e) {
            JOptionPane.showMessageDialog(myFrame, e.getMessage());
        }
    }

    private JMenu createFileMenu () {
        JMenu file = new JMenu("File");
        file.add(createLoadMenu());
        file.add(createFullScreenMenuItem());
        file.add(createCloseMenuItem());
        return file;
    }

    private JMenuItem createFullScreenMenuItem () {
        JMenuItem temp = new JMenuItem("Full Screen");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                myFrame.setExtendedState(Frame.MAXIMIZED_BOTH);
                myFrame.setUndecorated(true);
            }
        });
        return temp;
    }

    private JMenuItem createCloseMenuItem () {
        JMenuItem temp = new JMenuItem("Close");
        temp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                myFrame.dispose();
                System.exit(0);
            }
        });
        return temp;
    }

    private void askForSchool () {
        mySchool = JOptionPane.showInputDialog(myFrame, "Enter School:");
    }

    /**
     * 
     * @param chartOption the visualization we want to display
     * @param path file path to the data
     * @param school name of the school we want to view
     */
    private void displayChart (String chartOption, String path, String school) {
        AbstractOption chartData = myChartCreatorFactory.getObject(chartOption);
        chartData.setReferences(myModel, this, school);
        chartData.execute();
        updateDisplay();
    }
}
